#!/bin/bash
g++ -x c++ -o groupby - <<EOF
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;
typedef pair<string, int> PAIR;
bool cmp(const PAIR& v1, const PAIR & v2)
{
    return v1.second >= v2.second;
}

bool isFileExists_ifstream(string& name) 
{
    ifstream f(name.c_str());
    return f.good();
}

void write_file(string filename, string line)
{
    ofstream out(filename, ios::app);
    out<<line<<endl;
}

string dou2str(double a)
{
    stringstream ss;
    string str;
    ss<<a;
    ss>>str;
    return str;
}

string int2str(int a)
{
    stringstream ss;
    string str;
    ss<<a;
    ss>>str;
    return str;
}

//功能1用于合并子任务
void merge(string filename)
{
    string line;
    ifstream in(filename);
    string yaml="ya";
    string testbox="tb";
    double time=0;
    while(getline(in,line)) {
        istringstream str(line);
        vector<string>line_spi;
        while (str >> line) {
		    line_spi.push_back(line);
	}
        if(yaml!=line_spi[0]||testbox!=line_spi[2]) {//上一个任务已统计完
            if(yaml=="ya") {
                yaml=line_spi[0];//开始记录本行任务
                testbox=line_spi[2];
                time=stod(line_spi[3]);
            }
            else {
                string str=yaml+" "+dou2str(time);
                write_file(testbox+"-"+filename, str);//把上一个任务写入文件
                yaml=line_spi[0];//开始记录本行任务
                testbox=line_spi[2];
                time=stod(line_spi[3]);
            }
        }
        else {
            time+=stod(line_spi[3]);
        }
    }
    string str=yaml+" "+dou2str(time);
    write_file(testbox+"-"+filename, str);
}

//文件转化为k-v形式
void get_map(map<string, int>&m, string filename, vector<vector<string>>&tboxes)
{
    string line;
    int nn=0;
    ifstream in(filename);
    while(getline(in,line)) {
        istringstream str(line);
        vector<string>line_spi;
        while (str >> line)
	    line_spi.push_back(line);
        double tim=stod(line_spi[1]);
        if(tim==0) {
            tboxes[nn%tboxes.size()].push_back(line_spi[0]);
        }
        else {
            m.insert(pair<string, int>(line_spi[0], tim));
        }
    }
}

//找到最小值函数，每次找出最闲的队列
int findminp(vector<double>&a)
{
    int min=0;
    for(int i=0;i<a.size();i++) {
        if(a[min]>a[i]) {
            min=i;
        }
    }
    return min;
}

//贪心算法
void group(vector<vector<string>>&tboxes, vector<PAIR>&v)
{
    int n=tboxes.size();
    vector<double>box_tim(n);
    int min=0;
    for (auto i : v) {
	if(min<n) {
            tboxes[min].push_back(i.first);
            box_tim[min]+=i.second;
            min++;
        }
        else {
            min=findminp(box_tim);
            tboxes[min].push_back(i.first);
            box_tim[min]+=i.second;
        }
    }
}

//累加时间功能，可以算输入文件中任务总用时
double add_time(map<string, int>&m)
{
    double res=0;
    for (auto i : m) {
        res+=i.second;
    }
    return res;
}

//主函数
int main(int argc,char *argv[])
{ 
    if(argc==1||argc>3) {
        cout<<"You can execute this program by groupby.sh"<<endl;   
        return 0;
    }
    int choice=0;
    choice=atoi(argv[1]);
    string filename=argv[2];
    int box_num=0;
    vector<vector<string>>tboxes;
    if(choice==1) {
        merge(filename);
    }
    else if(choice==2) {
        cout<<"Please enter the number of testboxes: "<<endl;
        cin>>box_num;
        vector<string>emptylist;
        for(int i=0;i<box_num;i++) {
            tboxes.push_back(emptylist);
        }
        map<string, int> m;
        get_map(m,filename,tboxes);
        vector<PAIR>v(m.begin(), m.end());
        sort(v.begin(), v.end(), cmp);//任务运行时间排序
        group(tboxes, v);
        string tasklist="Taskgroup-"+filename;
        for(int i=0;i<tboxes.size();i++) {
            cout<<"box"<<i<<":"<<endl;
            write_file(tasklist,"box"+int2str(i)+":");
            string boxline="";
            for(int j=0;j<tboxes[i].size();j++) {
                cout<<""<<tboxes[i][j]<<" ";
                boxline=boxline+tboxes[i][j]+" ";
            }    
            write_file(tasklist,boxline);
            cout<<endl;
        }
    }
    else {
	cout<<"You can execute this program by groupby.sh"<<endl;
    }
    return  0;
}
EOF
case $1 in
    testbox)
        ./groupby 1 $2 ;;
    runtime)
        ./groupby 2 $2 ;;
    *)
        echo "Usage:"
        echo "1) testbox: Sort the tasks in the file by testbox type."
       	echo "	 ./groupby.sh testbox <FILE1>"
	echo "	 <FILE1> can be openeuler.txt, debian.txt or centos.txt"
	echo "2) runtime: Provides a task grouping scheme by runtime."
	echo "	 ./groupby.sh runtime <FILE2>"
	echo "	 <FILE2> can be the output file of 'groupby testbox'"
esac
